package cn.tedu.charging.device.service;

import cn.tedu.charging.common.pojo.po.ChargingGunInfoPO;
import cn.tedu.charging.common.pojo.po.ChargingStationPO;
import cn.tedu.charging.common.pojo.vo.GunInfoVO;
import cn.tedu.charging.common.pojo.vo.StationDetailVO;
import cn.tedu.charging.common.pojo.vo.StationInfoVO;
import cn.tedu.charging.device.dao.repository.GunRepository;
import cn.tedu.charging.device.dao.repository.StationRepository;
import com.alibaba.nacos.common.utils.CollectionUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.domain.geo.GeoLocation;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class StationService {
    @Autowired
    private StationRepository stationRepository;
    @Autowired
    private GunRepository gunRepository;
    //操作缓存 一种简单的用法 就是直接在业务层注入redisTemplate拿到想要的所有数据
    //但是中间加了一个仓储层 进行业务是实现的解耦  要求 所有数据读写处理 都经过仓储层完成
    public List<StationInfoVO> nearbyStations(Double longitude, Double latitude, Double radius) {
        //1.调用仓储层 查询缓存 命中的所有充电桩 geo数据 返回数据类型
        GeoResults<GeoLocation<Integer>> geoResults=stationRepository.nearbyStations(longitude,latitude,radius);
        //2.解析这个数据
        List<GeoResult<GeoLocation<Integer>>> contents = geoResults.getContent();
        //3.通过contents 命中的数据 一次封装返回值stationInfoVO数据 如果contents是非空才封装vo
        List<StationInfoVO> vos=null;
        if (CollectionUtils.isNotEmpty(contents)){
            log.debug("本次查询附近充电站,命中数据:{}个",contents.size());
            vos=new ArrayList<>();
            //方案一 转化contents stationInfoVOs 使用for循环
            for (GeoResult<GeoLocation<Integer>> content : contents) {
                StationInfoVO vo=new StationInfoVO();
                vo.setStationId(content.getContent().getName());
                //lng:x lat:y
                vo.setStationLng(new BigDecimal(content.getContent().getPoint().getX()));
                vo.setStationLat(new BigDecimal(content.getContent().getPoint().getY()));
                //distance 返回经度到达万分为 4个小数点,可以缩短到2位小数点
                vo.setDistance(content.getDistance().getValue());
                String stationName=stationRepository.getStationNameById(vo.getStationId());
                vo.setStationName(stationName);
                vos.add(vo);
            }
        }
        return vos;
    }

    public StationDetailVO detailStation(Integer stationId) {
        //1.查询仓储层 充电站 信息 预热缓存有po
        ChargingStationPO stationPO=stationRepository.getStationById(stationId);
        //2.判断po是否为空 为空异常结束
        if (stationPO==null){
            throw new RuntimeException("没有找到对应的充电站");
        }
        //3.po不为空 封装vo 2个属性 address stationName
        StationDetailVO vo=new StationDetailVO();
        vo.setAddress(stationPO.getAddress());
        vo.setStationName(stationPO.getStationName());
        //4.使用站场的id 查询与之关联的gun列表 转化 vo集合 枪数据缓存逻辑
        List<ChargingGunInfoPO> gunPos=gunRepository.getGunsByStationId(stationId);
        List<GunInfoVO> gunInfoVos=null;
        //使用非空集合 转化另一个集合 每个po元素 都在新的集合中 对应一个vo 一对一映射 可以使用上面业务for循环
        //这里 采用 stream()流api
        if (CollectionUtils.isNotEmpty(gunPos)){
            //filter过滤 把满足条件的元素留下
            //sort 使用对象之间属性判断排序
            //forEach 遍历集合元素
            //map 做新的集合映射
            //第二种方案 实现
            gunInfoVos=gunPos.stream().map(po->{
                //po 就是集合每个元素 做转化映射计算 换成vo
                GunInfoVO gunInfoVO=new GunInfoVO();
                BeanUtils.copyProperties(po,gunInfoVO);
                return gunInfoVO;
            }).collect(Collectors.toList());
            /*gunInfoVos=new ArrayList<>();
            for (ChargingGunInfoPO gunPo : gunPos) {
                GunInfoVO gunInfoVO=new GunInfoVO();
                gunInfoVO.setGunName(gunPo.getGunNumber());
                gunInfoVO.setGunStatus(gunPo.getGunStatus());
                gunInfoVO.setGunType(gunPo.getGunType());
                gunInfoVO.setElectriciy(gunPo.getElectricity());
                gunInfoVos.add(gunInfoVO);
            }*/
        }
        //5.vo封装完毕返回
        vo.setGunInfoPOList(gunInfoVos);
        return vo;
    }
}
